package com.platform.dbs.dto;

import com.google.common.base.Strings;
import com.platform.comm.dto.BaseQo;
import com.platform.comm.util.CryptUtil;
import com.platform.constants.PostgreSQLSettingField;
import com.platform.enums.CPSettingField;
import com.platform.enums.LinkType;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @author liujizheng
 * @version 1.0
 * @ClassName LinkMetadataDto
 * @Description 连接元数据dto
 * @date 2021/10/28 11:35
 */
@Slf4j
@EqualsAndHashCode(callSuper = true)
@Data
public class LinkMetadataDto extends BaseQo {

    /**
     * id
     */
    private String id;

    /**
     * name
     */
    private String name;

    /**
     * linkType
     */
    private String linkType;

    //private String dictKey;

    /**
     * linkCode
     */
    private String linkCode;

    /**
     * data
     */
    private Map<String, Object> data;

    /**
     * status
     */
    private String status;

    /**
     * createBy
     */
    private String createBy;

    /**
     * updateBy
     */
    private String updateBy;

    private boolean isDefault;

    /**
     * 获取方案信息
     *
     * @return
     */
    public String getSchemaName() {
        LinkType dtName = LinkType.value(linkType);
        if (null == dtName) {
            return (String) getData().get(PostgreSQLSettingField.DB_NAME.getField());
        }
        switch (dtName) {
            case PostgreSQL:
            case Greenplum:
                return (String) getData().get(PostgreSQLSettingField.DATA_SOURCE_SCHEMA.getField());
            default:
                return (String) getData().get(PostgreSQLSettingField.DB_NAME.getField());
        }
    }

    public void password64HeadEn() {
        String password = MapUtils.getString(this.getData(), PostgreSQLSettingField.PASSWORD.getField());
        if (StringUtils.isNotBlank(password)) {
            this.data.put(PostgreSQLSettingField.PASSWORD.getField(), CryptUtil.bs64EncryptWithHead(password));
        }
    }

    public void password64HeadDe() {
        String password = MapUtils.getString(this.getData(), PostgreSQLSettingField.PASSWORD.getField());
        if (StringUtils.isNotBlank(password)) {
            this.data.put(PostgreSQLSettingField.PASSWORD.getField(), CryptUtil.bs64DecryptWithHead(password));
        }
    }

    @Override
    public void init() {
        super.init();
        validateNumerics();
    }

    public void validateNumerics() {
        Long maxLifetime = MapUtils.getLong(this.getData(), CPSettingField.MAX_LIFETIME.getField());
        if (maxLifetime == null
                || (maxLifetime != 0L && maxLifetime < TimeUnit.SECONDS.toMillis(30L))) {
            log.warn("maxLifetime is less than 30000ms, setting to default {}ms.", CPSettingField.MAX_LIFETIME.getDefaultValue());
            this.getData().put(CPSettingField.MAX_LIFETIME.getField(), CPSettingField.MAX_LIFETIME.getDefaultValue());
            maxLifetime = CPSettingField.MAX_LIFETIME.getDefaultValue();
        }
        Long leakDetectionThreshold = MapUtils.getLong(this.getData(), CPSettingField.LEAK_DETECTION_THRESHOLD.getField());
        if (leakDetectionThreshold == null || (leakDetectionThreshold > 0L
                && (leakDetectionThreshold < TimeUnit.SECONDS.toMillis(2L)
                || leakDetectionThreshold > maxLifetime && maxLifetime > 0L))) {
            log.warn("leakDetectionThreshold is less than 2000ms or more than maxLifetime, disabling it.");
            leakDetectionThreshold = 0L;
            this.getData().put(CPSettingField.LEAK_DETECTION_THRESHOLD.getField(), 0L);
        }
        Long connectionTimeout = MapUtils.getLong(this.getData(), CPSettingField.CONNECTION_TIMEOUT.getField());
        if (connectionTimeout == null || connectionTimeout < 250L) {
            log.warn("connectionTimeout is less than 250ms, setting to {}ms.", CPSettingField.CONNECTION_TIMEOUT.getDefaultValue());
            connectionTimeout = CPSettingField.CONNECTION_TIMEOUT.getDefaultValue();
            this.getData().put(CPSettingField.CONNECTION_TIMEOUT.getField(), CPSettingField.CONNECTION_TIMEOUT.getDefaultValue());
        }
        Long validationTimeout = MapUtils.getLong(this.getData(), CPSettingField.VALIDATION_TIMEOUT.getField());
        if (validationTimeout == null || validationTimeout < 250L) {
            log.warn("validationTimeout is less than 250ms, setting to {}ms.", CPSettingField.VALIDATION_TIMEOUT.getDefaultValue());
            this.getData().put(CPSettingField.VALIDATION_TIMEOUT.getField(), CPSettingField.VALIDATION_TIMEOUT.getDefaultValue());
        }
        Long maxPoolSize = MapUtils.getLong(this.getData(), CPSettingField.MAX_POOL_SIZE.getField());
        if (maxPoolSize == null || maxPoolSize < 1) {
            this.getData().put(CPSettingField.MAX_POOL_SIZE.getField(), CPSettingField.MAX_POOL_SIZE.getDefaultValue());
            maxPoolSize = CPSettingField.MAX_POOL_SIZE.getDefaultValue();
        }
        Long minIdle = MapUtils.getLong(this.getData(), CPSettingField.MIN_IDLE.getField());
        if (minIdle == null || minIdle < 0 || minIdle > maxPoolSize) {
            minIdle = maxPoolSize;
            this.getData().put(CPSettingField.MIN_IDLE.getField(), maxPoolSize);
        }
        Long idleTimeout = MapUtils.getLong(this.getData(), CPSettingField.IDLE_TIMEOUT.getField());
        if (idleTimeout == null
                || (idleTimeout + TimeUnit.SECONDS.toMillis(1L) > maxLifetime && maxLifetime > 0L && minIdle < maxPoolSize)) {
            log.warn("idleTimeout is close to or more than maxLifetime, disabling it.");
            this.getData().put(CPSettingField.IDLE_TIMEOUT.getField(), 0L);
        } else if (idleTimeout != 0L && idleTimeout < TimeUnit.SECONDS.toMillis(10L) && minIdle < maxPoolSize) {
            log.warn("idleTimeout is less than 10000ms, setting to default {}ms.", CPSettingField.IDLE_TIMEOUT.getDefaultValue());
            this.getData().put(CPSettingField.IDLE_TIMEOUT.getField(), CPSettingField.IDLE_TIMEOUT.getDefaultValue());
        } else if (CPSettingField.IDLE_TIMEOUT.getDefaultValue().compareTo(idleTimeout) != 0 && idleTimeout != 0L && minIdle.equals(maxPoolSize)) {
            log.warn("idleTimeout has been set but has no effect because the pool is operating as a fixed size pool.");
        }

    }

    /**
     * 解密
     */
    public void passwordDe(){
        String password = (String) this.data.get(PostgreSQLSettingField.PASSWORD.getField());
        if(StringUtils.isNotBlank(password)){
            this.data.put(PostgreSQLSettingField.PASSWORD.getField(),CryptUtil.aesDecrypt(password));
        }
    }

    /**
     * 加密
     */
    public void passwordEn(){
        String password = (String) this.data.get(PostgreSQLSettingField.PASSWORD.getField());
        if(StringUtils.isNotBlank(password)){
            this.data.put(PostgreSQLSettingField.PASSWORD.getField(),CryptUtil.aesEncrypt(password));
        }
    }

    /**
     *  用于判断连接元数据是否变更
     * @return
     */
    public String getCheckCode(){
        Map<String, Object> settingMap = this.getData();
        StringBuffer sb = new StringBuffer();
        sb.append(MapUtils.getString(settingMap, PostgreSQLSettingField.DRIVER_CLASS.getField()))
                .append(MapUtils.getString(settingMap, PostgreSQLSettingField.URL.getField()))
                .append(MapUtils.getString(settingMap, PostgreSQLSettingField.USER_NAME.getField()))
                .append(MapUtils.getString(settingMap, PostgreSQLSettingField.PASSWORD.getField()));
        if (!Strings.isNullOrEmpty(MapUtils.getString(settingMap, PostgreSQLSettingField.DATA_SOURCE_SCHEMA.getField()))) {
            sb.append(MapUtils.getString(settingMap, PostgreSQLSettingField.DATA_SOURCE_SCHEMA.getField()));
        }
        // 配置数据源
        if (Objects.nonNull(settingMap.get(CPSettingField.MAX_POOL_SIZE.getField()))) {
            sb.append(MapUtils.getInteger(settingMap, CPSettingField.MAX_POOL_SIZE.getField()));
        }
        if (Objects.nonNull(settingMap.get(CPSettingField.MIN_IDLE.getField()))) {
            sb.append(MapUtils.getInteger(settingMap, CPSettingField.MIN_IDLE.getField()));
        }
        if (Objects.nonNull(settingMap.get(CPSettingField.IDLE_TIMEOUT.getField()))) {
            sb.append(MapUtils.getLong(settingMap, CPSettingField.IDLE_TIMEOUT.getField()));
        }
        if (Objects.nonNull(settingMap.get(CPSettingField.MAX_LIFETIME.getField()))) {
            sb.append(MapUtils.getLong(settingMap, CPSettingField.MAX_LIFETIME.getField()));
        }
        if (Objects.nonNull(settingMap.get(CPSettingField.VALIDATION_TIMEOUT.getField()))) {
            sb.append(MapUtils.getLong(settingMap, CPSettingField.VALIDATION_TIMEOUT.getField()));
        }
        if (Objects.nonNull(settingMap.get(CPSettingField.CONNECTION_TIMEOUT.getField()))) {
            sb.append(MapUtils.getLong(settingMap, CPSettingField.CONNECTION_TIMEOUT.getField()));
        }
        if (Objects.nonNull(settingMap.get(CPSettingField.LEAK_DETECTION_THRESHOLD.getField()))) {
            sb.append(MapUtils.getLong(settingMap, CPSettingField.LEAK_DETECTION_THRESHOLD.getField()));
        }
        return CryptUtil.digest(sb.toString());
    }
}
